package com.cheetah.handler;

import com.cheetah.client.CheetahClient;
import com.cheetah.client.ExponentialBackOffRetry;
import com.cheetah.client.RetryPolicy;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.EventLoop;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
@ChannelHandler.Sharable
@Slf4j
public class ReconnectHandler extends ChannelInboundHandlerAdapter {

    @Autowired
    private CheetahClient cheetahClient;
    private int retries = 0;
    private RetryPolicy retryPolicy;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        retries = 0;
        ctx.fireChannelActive();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        if (retries == 0) {
            log.error("Lost the TCP connection with the server.");
            ctx.close();
        }
        boolean allowRetry = getRetryPolicy().allowRetry(retries);
        if (allowRetry) {
            long sleepTimeMs = getRetryPolicy().getSleepTimeMs(retries);
            log.info("Try to reconnect to the server after {}ms. Retry count: {}.", sleepTimeMs, ++retries);
            final EventLoop eventLoop = ctx.channel().eventLoop();
            eventLoop.schedule(() -> {
                log.info("Reconnecting ...");
                cheetahClient.getClient();
            }, sleepTimeMs, TimeUnit.MILLISECONDS);
        }
        ctx.fireChannelInactive();
    }

    private RetryPolicy getRetryPolicy() {
        if (this.retryPolicy == null) {
            this.retryPolicy = new ExponentialBackOffRetry(1000,Integer.MAX_VALUE,4 * 60 * 1000 + 30 * 1000);
        }
        return this.retryPolicy;
    }
}